#include "Pcie_X1075.h"

#include "CxDeviceSDK.h"
#include "CalculateManager.h"

int cardCount = 0;                      // 扫描到可操作的板卡数量
CardInfo* cardInfoList = nullptr;       // 板卡信息
PXIeCard_DeviceHandle handle = nullptr; // 板卡句柄


Pcie_X1075::Pcie_X1075()
{

}

Pcie_X1075::~Pcie_X1075()
{

}

Pcie_X1075 pcie_X1075;

int Pcie_X1075::packeventCount[4] = { 0 };  // 初始化数组，所有元素默认为 0

// 假设每个通道存储五次电压数据
constexpr int MAX_SAMPLES = 5;
bool DataToCSV_State[5] = { false };
int packeventCount[5] = { 0 };    // 每通道的回调次数

// 使用一维数组存储每个通道的电压值
static double* voltageStorage[MAX_CHANNEL_NUMBER];  // 为每个通道存储一维数组 电压值

static char* WaveDataStorage[MAX_CHANNEL_NUMBER];  // 为每个通道存储一维数组 原始值
static int sampleCounter[MAX_CHANNEL_NUMBER] = { 0 }; // 用于计数每个通道存储的次数

static void loggevent(uint32_t level, const char* data)
{
	std::cout << "Level: " << level << ", Data: " << data << std::endl;
}

/**
 * @brief 板卡初始化
 *
 * 该函数扫描设备上的板卡，并对板卡进行初始化 返回必要信息
 *
 *
 * @return 成功返回 0，失败返回错误代码。
 */
int Pcie_X1075::CxDevice_Init(CardInfo* _CardInfo, int32_t* cardCount, CxDeviceHandle* hDevice)
{
	int err = 0;
	*cardCount = 0;
	*hDevice = nullptr;

	// 扫描板卡
	err = CxDeviceGetCardInfoList(&_CardInfo, cardCount);
	std::cout << "扫描到" << *cardCount << "块板卡" << std::endl;
	if (*cardCount <= 0 || err != 0)
	{
		std::cout << "Scan Error. " << std::endl;
		CxDeviceSDKDeInit();
		system("pause");
		return -80001;
	}

	// 打开扫描到的卡 并初始化
	for (int i = 0; i < *cardCount; ++i)
	{
		err = CxDeviceOpenCard(_CardInfo[i], hDevice);
		if (err != 0)
		{
			std::cout << "Open Error. " << std::endl;
			CxDeviceSDKDeInit();
			system("pause");
			return err;
		}
		// SlotID WIN PC 数量从 31 开始 
		std::cout << "已读取" << _CardInfo[i].SlotID << "号槽板卡的数据" << std::endl;

		// 板卡初始化
		err = CxDeviceInitCard(*hDevice);
		if (err != 0)
		{
			std::cout << "Init Error. " << std::endl;
			CxDeviceSDKDeInit();
			system("pause");
			return err;
		}
		std::cout << _CardInfo[i].SlotID << "号槽板卡初始化成功" << std::endl;
	}

	// 在此检查 handle 是否已经被正确赋值
	std::cout << "handle address 初始化: " << *hDevice << std::endl;
	return NOERROR;
}

/**
 * 通道设置
 */
void Pcie_X1075::Channel_Init(CxDeviceHandle* hDevice, uint8_t CH_Quantity)
{
	// 通道设置
	for (uint8_t ch = 1; ch <= CH_Quantity; ++ch)
	{
		// 通道初始化 4个通道
		ChannelConfiguration(hDevice,
			ch,
			Force,       // 触发源类型 强制触发
			Normal,      // 普通触发  AutoMode  Normal
			Rising,      // 外部触发极性    上升沿
			Rising,      // 触发极性        上升沿
			0,           // 触发位置，单位为 ns  触发点在触发长度中的位置，或者说是触发点前的数据长度
			20000000,     // 触发长度，单位为 ns  触发一次保存的窗口数据长度  (数据长度 = 触发长度 * 1.5 * 2)
			500,         // 触发电平，单位为 mV
			0,           // 触发窗口开始，单位为 ns
			1000000000,  // 触发窗口结束，单位为 ns
			10,          // 触发脉宽，单位为 ns
			4000,        // 量程，单位为 mV
			Fixed,       // 基线模式  TraceB  Fixed
			0,           // 偏置电压，单位为 mV  这个设置为样卡设置，新卡为0
			Load1M,      // 输入阻抗 1MΩ
			ACCoupling); // 耦合方式  AC
	}

	// 设置数据包回调函数
	CxDeviceSetChannelRecvCallback(*hDevice, 1, packevent);
	// 开始数据包回调接收
	CxDeviceStartChannelRecv(*hDevice, 1);

	for (uint8_t ch = 1; ch <= CH_Quantity; ++ch)
	{
		// 使能 4个通道
		ChannelReadEnabler(hDevice, ch);
	}
}

/**
 * @brief 通道级 配置
 *
 * @param hDevice                设备句柄。
 * @param chNo                   要配置的通道编号。
 * @param _TrigSource            设置触发源类型。
 *                                枚举值：
 *                                - LocalChannel：本地通道 (1)
 *                                - LocalBoard：本地板卡 (2)
 *                                - Global：全局触发 (4)
 *                                - External：外部触发 (8)
 *                                - Force：强制触发 (16)
 *                                - Cycle：周期触发 (32)
 * @param _TrigMode              设置触发模式。
 *                                枚举值：
 *                                - Finite：有限触发 (1)
 *                                - Normal：普通触发 (2)
 *                                - AutoMode：自动触发 (4)
 * @param _ExternalTrigPolarity  设置外部触发极性。
 *                                枚举值：
 *                                - Falling：下降沿 (0)
 *                                - Rising：上升沿 (1)
 * @param _TrigPolarity          设置触发极性。
 *                                枚举值：
 *                                - Falling：下降沿 (0)
 *                                - Rising：上升沿 (1)
 * @param _TrigPosition          设置触发位置，单位为 ns。
 * @param _TrigLength            设置触发长度，单位为 ns。
 * @param _TrigPulseWidth        设置触发脉宽，单位为 ns。
 * @param _VoltageRange          设置量程，单位为 mV。
 * @param _TrigBaselineMode      设置基线模式。
 * @param _VoltageOffset         设置偏置电压，单位为 mV。
 * @param _InputImpedance        设置输入阻抗。
 *                                枚举值：
 *                                - Load50：50 欧姆 (0)
 *                                - Load1M：1 兆欧姆 (1)
 * @param _CouplingMode          设置耦合方式。
 *                                枚举值：
 *                                - ACCoupling：交流耦合 (0)
 *                                - DCCoupling：直流耦合 (1)
 * @param _TrigLevel             设置触发电平，单位为 mV。
 * @param _TrigWindowStart       设置触发窗口开始，单位为 ns。
 * @param _TrigWindowEnd         设置触发窗口结束，单位为 ns。
 *
 * @return 成功返回 0，失败返回错误代码。
 */
int Pcie_X1075::ChannelConfiguration(CxDeviceHandle* hDevice,
	int32_t chNo,
	int32_t _TrigSource,
	int32_t _TrigMode,
	int32_t _ExternalTrigPolarity,
	int32_t _TrigPolarity,
	int32_t _TrigPosition,
	int32_t _TrigLength,
	int32_t _TrigLevel,
	int32_t _TrigWindowStart,
	int32_t _TrigWindowEnd,
	int32_t _TrigPulseWidth,
	int32_t _VoltageRange,
	int32_t _TrigBaselineMode,
	int32_t _VoltageOffset,
	int32_t _InputImpedance,
	int32_t _CouplingMode)
{
	int err = 0;

	// 触发源
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, TrigSource, _TrigSource);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80002;
	}
	// 触发模式
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, TrigMode, _TrigMode);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80003;
	}
	// 外触发极性
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, ExternalTrigPolarity, _ExternalTrigPolarity);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80004;
	}
	// 触发极性
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, TrigPolarity, _TrigPolarity);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80005;
	}
	// 触发位置，单位ns
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, TrigPosition, _TrigPosition);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80006;
	}
	// 触发长度，单位ns
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, TrigLength, _TrigLength);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80007;
	}
	// 触发电平，单位mV
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, TrigLevel, _TrigLevel);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80008;
	}
	// 触发窗口开始，单位ns（每个通道符合开窗范围，通道用户自定义，相对于SyncWindow的0点）
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, TrigWindowStart, _TrigWindowStart);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80009;
	}
	// 触发窗口结束，单位ns（相对于SyncWindow的0点）
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, TrigWindowEnd, _TrigWindowEnd);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80010;
	}
	// 触发脉宽，单位ns
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, TrigPulseWidth, _TrigPulseWidth);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80015;
	}
	// 电压量程，单位mV
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, VoltageRange, _VoltageRange);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80016;
	}
	// 基线模式
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, TrigBaselineMode, _TrigBaselineMode);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80017;
	}
	// 偏置电压，单位mV
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, VoltageOffset, _VoltageOffset);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80017;
	}
	// 输入阻抗，单位欧姆
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, InputImpedance, _InputImpedance);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80018;
	}
	// 耦合方式
	err = CxDeviceWriteChannelConfig(*hDevice, chNo, CouplingMode, _CouplingMode);
	if (err != 0)
	{
		CxDeviceSDKDeInit();
		system("pause");
		return -80019;
	}
	//}
	std::cout << "通道 " << chNo << "初始化完成 " << std::endl;
	return NOERROR;
}

/**
 * @brief 指定通道 接收开启
 *
 * @param hDevice                设备句柄。
 * @param chNo                   要配置的通道编号。
 *
 *
 * @return 成功返回 0，失败返回错误代码。
 */
int Pcie_X1075::ChannelReadEnabler(CxDeviceHandle* hDevice, int32_t chNo)
{
	int err = 0;

	// 使能
	err = CxDeviceEnableChannel(*hDevice, chNo);
	if (err != 0)
	{
		std::cout << "Enable Error. " << std::endl;
		CxDeviceSDKDeInit();
		system("pause");
		return err;
	}
	std::cout << "Enable Successfully. " << std::endl;
	return NOERROR;
}

/**
 * @brief 指定通道 接收停止
 *
 * @param hDevice                设备句柄。
 * @param chNo                   要配置的通道编号。
 */
int Pcie_X1075::ChannelReadStop(CxDeviceHandle* hDevice, int32_t chNo)
{
	int err = 0;

	// 失能
	err = CxDeviceDisableChannel(*hDevice, chNo);
	if (err != 0)
	{
		std::cout << "Disable Error. " << std::endl;
		CxDeviceSDKDeInit();
		system("pause");
		return err;
	}
	std::cout << "Disable Successfully. " << std::endl;
	return NOERROR;
}

/**
 * @brief 指定通道 软件触发
 *
 * @param hDevice                设备句柄。
 * @param chNo                   要配置的通道编号。
 */
int Pcie_X1075::ChannelSoftwareTrigger(CxDeviceHandle* hDevice, int32_t chNo)
{
	int err = 0;
	err = CxDeviceSendChannelSoftwareTrigger(*hDevice, chNo);
	return err;
}

/**
 * @brief 获取当前时间字符串，格式为 "DDMMYY_HHMMSSmmm"
 *
 * @return std::string 返回格式化的时间字符串
 */
using namespace std;
static std::string getCurrentTimeStr()
{
	// 获取当前时间点
	auto now = std::chrono::system_clock::now();
	// 获取从纪元开始的时间跨度
	auto duration = now.time_since_epoch();
	// 转换为毫秒
	auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
	// 获取当前时间的秒数  格式化为年、月、日、时、分、秒、毫秒的形式
	std::time_t now_c = std::chrono::system_clock::to_time_t(now);
	// 使用 localtime_s 获取安全的本地时间
	std::tm timeStruct; // 本地时间结构体
	localtime_s(&timeStruct, &now_c);

	// 格式化时间
	std::ostringstream stream;
	// 使用 std::setw 和 std::setfill 来补充零  毫秒部分始终显示为3位数，用零填充不足宽度的部分
	stream << std::put_time(&timeStruct, "%y%m%d_%H%M%S")
		<< std::setw(3) << std::setfill('0') << milliseconds.count() % 1000; // 获取毫秒部分并补充零
	return stream.str();
}

/**
 * @brief 处理接收到的数据包并将其存入对应的通道队列
 *
 * 该函数用于接收一个数据包，根据数据包中的通道号和数据大小，验证其有效性并将数据压入对应通道的队列中。
 * 如果数据包的通道号无效或数据大小超过最大限制，则不会执行入队操作。
 *
 * @param package 指向一个 `SciAcqPackage` 类型的指针，表示接收到的数据包。数据包包含了通道号、数据大小以及波形数据等信息。
 *
 * @note
 * - 函数首先检查传入的通道号是否合法，并确保数据大小不超过预设的最大值。
 * - 如果队列未满，则将数据包压入对应的通道队列。
 * - 如果队列已满或数据包无效，函数会返回并不做任何操作。
 */
void Pcie_X1075::packevent(SciAcqPackage* package)
{
	// 取通道号  数据包是从 0 开始的 1 通道  确保通道号在有效范围内
	uint16_t ch = package->ChannelId;
	if (ch >= MAX_CHANNEL_NUMBER)
	{
		// 如果通道号无效，处理错误
		std::cerr << "Error: Invalid channel ID: " << ch << std::endl;
		return;
	}

	// 检查 dataSize 的最大大小（假设每个通道的最大点数为 MAX_POINT_COUNT）
	int32_t dataSize = package->WaveDataSize;
	if (dataSize > MAX_POINT_COUNT)
	{
		// 如果 dataSize 超过了 RawDataList 可容纳的最大数据量，则打印错误信息或做其他处理
		std::cerr << "Error: RawDataSize exceeds the maximum allowed size." << std::endl;
		return;
	}

	auto& WaveDataWrapper_queue = *WaveDataWrapperQueue[ch];
	if (!WaveDataWrapper_queue.isFull()) {
		// 创建一个新的 WaveDataWrapper，并对 package 进行深拷贝 将 package->WaveData 转为智能指针
		auto WaveData_Wrapper = std::make_unique<WaveDataWrapper>();

		// 拷贝其他参数
		WaveData_Wrapper->ADCDigitOffset = package->ADCDigitOffset;
		WaveData_Wrapper->ADCPrecision = package->ADCPrecision;
		WaveData_Wrapper->ADCPreGain = package->ADCPreGain;
		WaveData_Wrapper->ADCRange = package->ADCRange;
		WaveData_Wrapper->BoardType = package->BoardType;
		WaveData_Wrapper->ChannelId = package->ChannelId;
		WaveData_Wrapper->DecodeMode = package->DecodeMode;
		WaveData_Wrapper->PackType = package->PackType;
		WaveData_Wrapper->Resolution = package->Resolution;
		WaveData_Wrapper->SampleFrequenceMHz = package->SampleFrequenceMHz;
		WaveData_Wrapper->SlotId = package->SlotId;
		WaveData_Wrapper->TimestampFine = package->TimestampFine;
		WaveData_Wrapper->TimestampNanosecond = package->TimestampNanosecond;
		WaveData_Wrapper->TimestampSecond = package->TimestampSecond;
		WaveData_Wrapper->TriggerId = package->TriggerId;
		WaveData_Wrapper->WaveDataSize = package->WaveDataSize;

		// 确保为 WaveData 分配内存
		WaveData_Wrapper->WaveData = std::make_unique<char[]>(WaveData_Wrapper->WaveDataSize);

		// 将 package->WaveData 中的数据拷贝到 WaveData_Wrapper->WaveData
		std::memcpy(WaveData_Wrapper->WaveData.get(), package->WaveData, WaveData_Wrapper->WaveDataSize);

		// 将深拷贝后的数据压入队列
		WaveDataWrapper_queue.push(std::move(WaveData_Wrapper));
		std::cerr << "WaveDataWrapperQueue 新数据压入: " << (int)ch << std::endl;
	}
	else
	{
		// 队列满了，无法压入数据
		std::cerr << "WaveDataWrapperQueue 已满，无法压入数据" << std::endl;
		return;
	}
}

/**
 * @brief 打印数组中的值
 *
 */
void Pcie_X1075::printVoltageList(double* voltage_List, int data_Length)
{
	// 遍历 voltage_List 数组，打印每个值
	for (int i = 0; i < data_Length; ++i)
	{
		std::cout << "Voltage[" << i << "]: " << voltage_List[i] << std::endl;
	}
}











